package com.hotchpotch.okHttp;

import android.os.Environment;
import android.os.Handler;
import android.os.Looper;

import com.hotchpotch.base.MyApplication;
import com.hotchpotch.util.BitmapUtils;
import com.hotchpotch.util.JsonUtil;
import com.hotchpotch.util.Logg;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Created by Administrator on 2017/7/6 0006.
 */

public class MyOkHttp {
    private static MyOkHttp myOkHttp = new MyOkHttp();
    private OkHttpClient client;//创建okHttpClient对象
    private Handler handler = new Handler(Looper.getMainLooper());

    public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
    public static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");

    private MyOkHttp() {
        initOkHttpClient();
    }

    public static MyOkHttp getInstence() {
        return myOkHttp;
    }

    private void initOkHttpClient() {
        File sdcache = MyApplication.getContext().getExternalCacheDir();
        int cacheSize = 10 * 1024 * 1024;
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)
                .connectTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(20, TimeUnit.SECONDS)
                .readTimeout(20, TimeUnit.SECONDS)
                .addInterceptor(new RetryIntercepter(10))
                .addNetworkInterceptor(new RetryIntercepter(10))
                .cache(new Cache(sdcache.getAbsoluteFile(), cacheSize));
        client = builder.build();
    }

    /**
     * 外部调用的get
     *
     * @param url
     * @param onOkHttpResultListener
     */
    public void doGet(String url, OkHttpResultCallBack onOkHttpResultListener) {
        getAsynHttp(url, onOkHttpResultListener);
    }

    /**
     * 外部调用的post方法
     *
     * @param url
     * @param formBody
     * @param onOkHttpResultListener
     */
    public void doPost(String url, RequestBody formBody, OkHttpResultCallBack onOkHttpResultListener) {
        postAsynHttp(url, formBody, onOkHttpResultListener);
    }

    /**
     * 外部调用的上传方法
     *
     * @param url
     * @param mediaType
     * @param fileUrl
     * @param onOkHttpResultListener
     */
    public void doUpload(String url, MediaType mediaType, String fileUrl, OkHttpResultCallBack onOkHttpResultListener) {
        postAsynFile(url, mediaType, fileUrl, onOkHttpResultListener);
    }

    /**
     * 外部调用的上传多文件
     *
     * @param url
     * @param imgs
     * @param onOkHttpResultListener
     */
    public void doMultipart(String url, List<String> imgs, OkHttpResultCallBack onOkHttpResultListener) {
        sendMultipart(url, imgs, onOkHttpResultListener);
    }

    /**
     * 外部调用上传图片以base64
     *
     * @param url
     * @param formBody
     * @param onOkHttpResultListener
     */
    public void doPostImgForBase64(String url, RequestBody formBody, OkHttpResultCallBack onOkHttpResultListener) {
        sendImg(url, formBody, onOkHttpResultListener);
    }

    /**
     * 外部调用的下载方法
     *
     * @param url
     * @param fileName
     * @param onOkHttpResultListener
     */
    public void doDownLoad(String url, final String fileName, OkHttpResultCallBack onOkHttpResultListener) {
        downAsynFile(url, fileName, onOkHttpResultListener);
    }

    /**
     * 异步get
     */
    private void getAsynHttp(String url, OkHttpResultCallBack onOkHttpResultListener) {
        Request.Builder requestBuilder = new Request.Builder().url(url);
        //可以省略，默认是GET请求
        requestBuilder.method("GET", null);
        execute(requestBuilder, onOkHttpResultListener);
    }

    /**
     * 异步post
     * RequestBody formBody = new FormBody.Builder().add("size", "10").build();(formBody的写法)
     */
    private void postAsynHttp(String url, RequestBody formBody, OkHttpResultCallBack onOkHttpResultListener) {
        Request.Builder builder = new Request.Builder()
                .url(url)
                .post(formBody);
//        Request request = builder.build();
        execute(builder, onOkHttpResultListener);
    }

    /**
     * 异步上传文件
     */
    private void postAsynFile(String url, MediaType mediaType, String fileUrl, OkHttpResultCallBack onOkHttpResultListener) {
        File file = new File(fileUrl);
        Request.Builder builder = new Request.Builder()
                .url(url)
                .post(RequestBody.create(mediaType, file));
        execute(builder, onOkHttpResultListener);
    }

    /**
     * 异步上传多张图片文件
     *
     * @param url
     * @param imgs
     * @param onOkHttpResultListener
     */
    private void sendMultipart(String url, List<String> imgs, final OkHttpResultCallBack onOkHttpResultListener) {
        MultipartBody.Builder mbody = new MultipartBody.Builder().setType(MultipartBody.FORM);
        List<File> fileList = new ArrayList<File>();
        for (String imgUrl : imgs) {
            fileList.add(new File(BitmapUtils.compressImageUpload(imgUrl)));
        }
        int i = 0;
        for (File file : fileList) {
            if (file.exists()) {
                Logg.e("imageName:", file.getName());//经过测试，此处的名称不能相同，如果相同，只能保存最后一个图片，不知道那些同名的大神是怎么成功保存图片的。
                mbody.addFormDataPart("image" + i, file.getName(), RequestBody.create(MEDIA_TYPE_PNG, file));
                i++;
            }
        }
        RequestBody requestBody = mbody.build();
        Request.Builder builder = new Request.Builder()
                .header("Authorization", "Client-ID " + "...")
                .url(url)
                .post(requestBody);

        client.newCall(builder.build()).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Logg.i("okHttp", "onFailure");
                call.cancel();
                onError(onOkHttpResultListener, e.getMessage());
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //从response从获取服务器返回的数据，转成字符串处理
                if (response.isSuccessful()) {
                    onSuccess(onOkHttpResultListener, response.body().string());
                } else {
                    onError(onOkHttpResultListener, response.message());
                }
            }
        });//加入调度队列
        BitmapUtils.deleteCacheFile();
    }

    /**
     * 传送图片已Base64编码格式
     *
     * @param url
     * @param onOkHttpResultListener
     */
    private void sendImg(String url, RequestBody requestBody, final OkHttpResultCallBack onOkHttpResultListener) {
        /*try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            //将bitmap一字节流输出 Bitmap.CompressFormat.PNG 压缩格式，100：压缩率，baos：字节流
            photodata.compress(Bitmap.CompressFormat.PNG, 100, baos);
            baos.close();
            byte[] buffer = baos.toByteArray();
            Log.e("图片的大小", buffer.length + "");
            //将图片的字节流数据加密成base64字符输出
            String photo = Base64.encodeToString(buffer, 0, buffer.length,Base64.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        Request.Builder builder = new Request.Builder()
                .url(url)
                .post(requestBody);

        execute(builder, onOkHttpResultListener);
    }

    /**
     * 异步下载文件(未修改)
     *
     * @param url
     * @param fileName 格式：/xxx.xxx
     */
    private void downAsynFile(String url, final String fileName, OkHttpResultCallBack onOkHttpResultListener) {
//        String url = "http://img.my.csdn.net/uploads/201603/26/1458988468_5804.jpg";
        Request request = new Request.Builder().url(url).build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) {
                InputStream inputStream = response.body().byteStream();
                FileOutputStream fileOutputStream = null;
                try {
                    fileOutputStream = new FileOutputStream(new File(Environment.getDownloadCacheDirectory().getPath().toString() + fileName));
                    byte[] buffer = new byte[2048];
                    int len = 0;
                    while ((len = inputStream.read(buffer)) != -1) {
                        fileOutputStream.write(buffer, 0, len);
                    }
                    fileOutputStream.flush();
                } catch (IOException e) {
                    Logg.i("okHttp", "IOException");
                    e.printStackTrace();
                }
                Logg.d("okHttp", "文件下载成功");
            }
        });
    }

    /**
     * 执行请求
     *
     * @param builder
     */
    private void execute(Request.Builder builder, final OkHttpResultCallBack callBack) {
        Call call = client.newCall(builder.build());
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Logg.e("okHttp", "onFailure");
                e.printStackTrace();
//                handler.post(retryRunnable);
                onError(callBack, e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                handler.removeCallbacks(retryRunnable);
                //从response从获取服务器返回的数据，转成字符串处理
                if (response.isSuccessful()) {
                    onSuccess(callBack, response.body().string());
                }
            }
        });//加入调度队列
    }

    private Runnable retryRunnable = new Runnable() {
        @Override
        public void run() {
            Logg.e("okhttp", "执行无网络重试 ---");
            client.retryOnConnectionFailure();
        }
    };

    /**
     * 监听
     */
    public abstract static class OkHttpResultCallBack<T> {
        // 成功回调
        public abstract void onSuccess(T data);

        // 失败回调
        public abstract void onError(String msg);
    }

    private void onSuccess(final OkHttpResultCallBack callback, final String data) {
        if (null != callback) {
            handler.post(new Runnable() {
                public void run() {
                    // 需要在主线程的操作。
                    callback.onSuccess(data);
                }
            });
        }
    }

    private void onError(final OkHttpResultCallBack callback, final String msg) {
        if (null != callback) {
            handler.post(new Runnable() {
                public void run() {
                    // 需要在主线程的操作。
                    callback.onError(msg);
                }
            });
        }
    }

    /**
     * 重试拦截器
     */
    private class RetryIntercepter implements Interceptor {

        public int maxRetry;//最大重试次数
        private int retryNum = 0;//假如设置为3次重试的话，则最大可能请求4次（默认1次+3次重试）

        public RetryIntercepter(int maxRetry) {
            this.maxRetry = maxRetry;
        }

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Logg.e("okhttp", "重试次数 = " + retryNum);
            Response response = chain.proceed(request);
            while (!response.isSuccessful() && retryNum < maxRetry) {
                retryNum++;
                Logg.e("okhttp", "循环中重试次数 = " + retryNum);
                response = chain.proceed(request);
            }
            return response;
        }
    }
}
